#include "stdafx.h"
#ifdef LIT_OGRE_SUPPORT
#include <LitSceneSelection.h>
#include <LitMovable.h>
#include <OgreSceneNode.h>
#include <OgreMovableObject.h>

namespace Lit
{
	SceneSelection::SceneSelection( ){}
	SceneSelection::SceneSelection( MovablePtr& lst ){sel.push(lst);}
	SceneSelection::SceneSelection( const MovablePtrList& lst ):sel(lst){}
	SceneSelection::SceneSelection( const SceneSelection& rk ):sel(rk.sel){}
	SceneSelection::~SceneSelection( ){ clearSelection(true); }
		
	MovablePtr SceneSelection::lowestObject() const{
		float h = 999999.99f;
		MovablePtr ret;
		for( auto j=sel.begin(); j!=sel.end(); j++ ){
			float h2 = j->get()->getPosition().y;
			if( h2 < h ) ret = (*j);
			h = std::min<float>( h, h2 );
		}
		return ret;
	}
	MovablePtr SceneSelection::highestObject() const{
		float h = -999999.99f;
		MovablePtr ret;
		for( auto j=sel.begin(); j!=sel.end(); j++ ){
			float h2 = j->get()->getPosition().y;
			if( h2 > h ) ret = (*j);
			h = std::max<float>( h, h2 );
		}
		return ret;
	}
	Vec3 SceneSelection::lowestPoint() const{
		Vec3 h(999999.99f);
		for( auto j=sel.begin(); j!=sel.end(); j++ ){
			Vec3 h2 = j->get()->getPosition();
			h = ((h2.y<h.y)?h2:h);
		}
		return h;
	}
	Vec3 SceneSelection::highestPoint() const{
		Vec3 h(-999999.99f);
		for( auto j=sel.begin(); j!=sel.end(); j++ ){
			Vec3 h2 = j->get()->getPosition();
			h = ((h2.y>h.y)?h2:h);
		}
		return h;
	}
	Ogre::Vector3 SceneSelection::center() const
	{
		Ogre::Vector3 ret = Ogre::Vector3::ZERO;
		if( !sel.empty() )
		{
			for( auto j=sel.begin(); j!=sel.end(); j++ )
				ret+=j->get()->getPosition();
			ret /=sel.size();
		}
		return ret;
	}
	Ogre::AxisAlignedBox SceneSelection::getBoundingBox() const
	{
		if( sel.empty() )  return Ogre::AxisAlignedBox::BOX_NULL;
		Ogre::AxisAlignedBox box;
		for( auto i=sel.begin(); i!=sel.end(); i++ )
			box.merge( i->get()->getBoundingBox() );
		return box;
	}
	MovablePtrList::Itor SceneSelection::begin(){ return sel.begin(); }
	MovablePtrList::Itor  SceneSelection::end(){return sel.end();}
	MovablePtrList::ConstItor SceneSelection::begin() const{ return sel.begin(); }
	MovablePtrList::ConstItor SceneSelection::end() const{return sel.end();}
		
	void SceneSelection::setPosition( const Ogre::Vector3 &pos, bool offset_by_bbox )
	{
		Ogre::Vector3 offset, ctr(center());
		for( MovablePtrList::Itor i=begin(); i!=end(); i++ )
		{
			offset = i->get()->getPosition()-ctr;
			if( offset_by_bbox ) i->get()->setPosition( pos+offset+ Lit::Vec3(0.0f, i->get()->getBoundingBox().getHalfSize().y, 0.0f) );
			else i->get()->setPosition( pos+offset );
		}
	}
	void SceneSelection::clearSelection(bool unselect){
		if( unselect && !sel.empty() )
		{
			try{
				for( size_t i=0; i<sel.size(); i++ )
				{
					if( sel.at(i) )
					{
						MovablePtr p(sel.at(i));
						if( p && p->getNode() ) p->getNode()->showBoundingBox( false );
					}
				}
			}
			catch( ... ){}
		}
		sel.clear();
		mCenter = Ogre::Vector3::ZERO;
	}
	void SceneSelection::setSelectionVisible(bool state)
	{
		for( size_t i=0; i<sel.size(); i++ )
		{
			MovablePtr p(sel.at(i));
			if( p ) p->getNode()->setVisible( state );
		}
	}
	bool SceneSelection::isSelectionVisible() const
	{
		for( size_t i=0; i<sel.size(); i++ )
		{
			MovablePtr p(sel.at(i));
			if( p && p->getNode()->getAttachedObject(0) && !p->getNode()->getAttachedObject(0)->isVisible() ) return false;
		}
		return true;
	}
	void SceneSelection::setSelected( MovablePtr p, bool state )
	{
		if( !p ) return;
		MovablePtrList::Itor i( sel.find(p) );
		if( i==sel.end() && state )
		{
			sel.push( p );
		}
		else if( !state ) sel.erase(i);
			
		if( p->getNode() ) p->getNode()->showBoundingBox( state );
	}

	MovablePtrList& SceneSelection::list(){ return sel; }
	const MovablePtrList& SceneSelection::list() const{ return sel; }

	bool SceneSelection::isSingleSelection() const{ return size() == 1; }
	MovablePtr::Ptr SceneSelection::singleSelection(){ if( sel.empty() ) return NULL; return sel.at(0).get(); }
	void SceneSelection::setSingleSelection( MovablePtr mov )
	{
		clearSelection();
		setSelected( mov, true );
	}
	bool SceneSelection::isSelected( MovablePtr p ) const
	{
		return sel.find(p) != sel.end();
	}
	size_t SceneSelection::size() const{ return sel.size(); }
	bool SceneSelection::empty() const{ return sel.empty(); }

	SceneSelection::operator bool() const{ return !empty(); }
	bool SceneSelection::operator == ( const SceneSelection & rk ) const
	{
		if( rk.size() != size() ) return false;
		MovablePtrList::ConstItor i(sel.begin());
		MovablePtrList::ConstItor ri( rk.sel.begin() );
		for( i; i!=sel.end(); i++ )
		{
			if( *i != *ri ) return false;
		}
		return true;
	}
	bool SceneSelection::operator != ( const SceneSelection & rk ) const
	{
		if( rk.size() != size() ) return true;
		MovablePtrList::ConstItor i(sel.begin());
		MovablePtrList::ConstItor ri( rk.sel.begin() );
		for( i; i!=sel.end(); i++ )
		{
			if( *i != *ri ) return true;
		}
		return false;
	}

		
	LIT_API std::ostream& operator << ( std::ostream& strm, const SceneSelection& sel ){
		strm << "Selection:" << std::endl << "\tcontains{ ";
		for( auto i=sel.begin(); i!=sel.end(); i++ )
		{
			strm << i->get()->getName() << (((i+1)==sel.end()) ? "" : ", ");
		}
		strm << " }" << std::endl;
		strm << "Lowest Point: " << sel.lowestPoint() << std::endl;
		strm << "Highest Point: " << sel.highestPoint() << std::endl;
		strm << "Center: " << sel.center();
		return strm;
	}
};

#endif